<?php
/**
 * TypeRepo.php
 *
 * @copyright   2023 thingsworld.com.cn - All Rights Reserved
 * @link        http://thingsworld.com.cn/
 * @author      stiffer.chen <chenl@thingsworld.com.cn>
 * @created     2023-02-14 00:01:50
 * @modified    2023-02-14 00:01:50
 *
 */

namespace App\Repositories\Product;

use App\Models\ArticleModel;
use App\Models\Product\Bom;
use App\Models\Product\Category;
use App\Models\Product\Type;
use App\Services\ImageServ;
use Carbon\Carbon;

class TypeRepo
{
    const START_TYPE_CODE_DATE_BUY = 'date_buy';
    const START_TYPE_CODE_DATE_CHECK = 'date_check';
    const START_TYPE_CODE_AFTER_SIX = 'after_six';

    const START_TYPE_TITLE_DATE_BUY = '购买日期';
    const START_TYPE_TITLE_DATE_CHECK = '验收日期';
    const START_TYPE_TITLE_AFTER_SIX = '购买后6个月';

    const START_TYPE_CODES = [
        self::START_TYPE_CODE_DATE_BUY,
        self::START_TYPE_CODE_DATE_CHECK,
        self::START_TYPE_CODE_AFTER_SIX
    ];

    const START_TYPE_TITLES = [
        self::START_TYPE_TITLE_DATE_BUY,
        self::START_TYPE_TITLE_DATE_CHECK,
        self::START_TYPE_TITLE_AFTER_SIX
    ];

    const START_UNIT_CODE_YEAR = 'year';
    const START_UNIT_CODE_MONTH = 'month';

    const START_UNIT_TITLE_YEAR = '按年';
    const START_UNIT_TITLE_MONTH = '按月';

    const START_UNIT_CODES = [
        self::START_UNIT_CODE_YEAR,
        self::START_UNIT_CODE_MONTH
    ];

    const START_UNIT_TITLES = [
        self::START_UNIT_TITLE_YEAR,
        self::START_UNIT_TITLE_MONTH
    ];

    public static function params()
    {
        return [
            'type_codes' => self::START_TYPE_CODES,
            'type_titles' => self::START_TYPE_TITLES,
            'start_types' => [
                [
                    'code' => self::START_TYPE_CODE_DATE_BUY,
                    'title' => self::START_TYPE_TITLE_DATE_BUY
                ],
                [
                    'code' => self::START_TYPE_CODE_DATE_CHECK,
                    'title' => self::START_TYPE_TITLE_DATE_CHECK
                ],
                [
                    'code' => self::START_TYPE_CODE_AFTER_SIX,
                    'title' => self::START_TYPE_TITLE_AFTER_SIX
                ]
            ],
            'unit_codes' => self::START_UNIT_CODES,
            'unit_titles' => self::START_UNIT_TITLES,
            'start_units' => [
                [
                    'code' => self::START_UNIT_CODE_YEAR,
                    'title' => self::START_UNIT_TITLE_YEAR
                ],
                [
                    'code' => self::START_UNIT_CODE_MONTH,
                    'title' => self::START_UNIT_TITLE_MONTH
                ]
            ]
        ];
    }

    public static function getList()
    {
        $perPage = (int)request('limit');
        if ($perPage < 1) {
            $perPage = 1;
        }

        $builder = Type::query();

        $builder->with(['boms.bom', 'category', 'articles.article.cate']);

        $name = trim(request()->get('name') ?? '');
        $queryCategoryId = request()->get('category_id');
        $categoryId = 0;
        if (!is_null($queryCategoryId)) {
            $categoryId = intval($queryCategoryId ?? 0);
        }
        $categoryName = trim(request()->get('category_name') ?? '');
        $warrantyStartType = trim(request()->get('warranty_start_type') ?? '');

        if ($name) {
            $builder->where('name', 'like', "%{$name}%");
        }
        if (!is_null($queryCategoryId)) {
            $builder->where('category_id', $categoryId);
        }
        if ($categoryName) {
            $builder->where('category_name', 'like', "%{$categoryName}%");
        }
        if ($warrantyStartType) {
            $builder->where('warranty_start_type', $warrantyStartType);
        }
        $builder->orderByDesc('update_time');
        $builder->orderByDesc('create_time');
        $result =  $builder->paginate($perPage);
        $result->transform(function($item) {
            return self::detail($item);
        });
        return $result;
    }

    public static function fetch($id)
    {
        $type = Type::with(['articles.article.cate', 'boms.bom'])->find($id);
        if (empty($type)) {
            throw new \Exception('类型不存在');
        }
        return self::detail($type);
    }

    public static function detail($type)
    {
        $articles = $type->articles;
        $typeArticles = [];
        foreach ($articles as $article) {
            $articleInfo = (new ArticleModel())->getInfo($article->article->id ?? 0);
            $typeArticles[] = [
                'id' => $article->article->id ?? 0,
                'title' => $articleInfo['title'] ?? '',
                'guide' => $articleInfo['guide'] ?? '',
                'cover' => $articleInfo['cover'] ?? '',
                'cover_image' => (new ImageServ($article->article->cover ?? ''))->getUrl(),
                'cate_id' => $article->article->cate_id ?? 0,
                'cate_name' => $article->article->cate->name ?? '',
                'content' => html_entity_decode($articleInfo['content'] ?? '', ENT_QUOTES, 'UTF-8'),
                'create_user_id' => $article->article->create_user ?? 0,
                'create_user_name' => $article->article->create_user_object->realname ?? '',
                'create_time' => Carbon::parse($article->create_time)->toDateTimeString(),
            ];
        }

        $boms = $type->boms;

        $typeBoms = [];
        if ($boms->count()) {
            foreach ($boms as $bom) {
                $bomId = $bom->bom->id ?? 0;
                if (!$bomId) {
                    continue;
                }
                $itemBom = Bom::find($bomId);
                if (empty($itemBom)) {
                    continue;
                }
                $bomDetail = BomRepo::getDetail($itemBom);
                if (!$bomDetail) {
                    continue;
                }
                $bomDetail['count'] = $bom->count;
                $typeBoms[] = $bomDetail;
            }
        }

        return [
            'id' => $type->id,
            'type_number' => $type->type_number,
            'category_id' => $type->category_id,
            'category_name' => $type->category->name ?? '',
            'name' => $type->name,
            'intro' => $type->intro,
            'image' => $type->image,
            'image_url' => (new ImageServ($type->image))->getUrl(),
            'warranty_start_type' => $type->warranty_start_type,
            'warranty_cycle_count' => $type->warranty_cycle_count,
            'warranty_start_unit' => $type->warranty_start_unit,
            'create_user_id' => $type->create_user_id,
            'create_user_name' => $type->user->realname ?? '',
            'create_time' => Carbon::parse($type->create_time)->toDateTimeString(),
            'update_time' => Carbon::parse($type->update_time)->toDateTimeString(),
            'articles' => $typeArticles,
            'boms' => $typeBoms
        ];
    }

    public static function store($id)
    {
        $data = self::requestData($id);
        $typeData = $data['main_data'];
        if ($id) {
            $type = Type::find($id);
        } else {
            $type = new Type();
        }

        if (empty($type)) {
            $type = new Type();
        }

        $boms = $data['boms'] ?? [];
        $typeBoms = [];
        foreach ($boms as $bom) {
            $typeBoms[] = new Type\Bom($bom);
        }
        $articles = [];
        foreach ($data['article_ids'] ?? [] as $articleId) {
            $articles[] = new Type\Article([
                'article_id' => $articleId
            ]);
        }

        $type->fill($typeData);
        $type->saveOrFail();

        $type->articles()->delete();
        if ($articles) {
            $type->articles()->saveMany($articles);
        }

        $type->boms()->delete();
        if ($typeBoms) {
            $type->boms()->saveMany($typeBoms);
        }

        return self::fetch($type->id);
    }

    private static function requestData($id)
    {
        $typeData = request()->getContent();
        $typeArr = json_decode($typeData, true);

        $categoryId = intval($typeArr['category_id'] ?? 0);
        $category = Category::find($categoryId);
        if (empty($category)) {
            throw new \Exception('请选择产品分类');
        }

        $name = trim($typeArr['name'] ?? '');
        if (!$name) {
            throw new \Exception('类型名称必填');
        }

        $nameType = Type::byName($name)->first();
        if ($nameType && $nameType->id != $id) {
            throw new \Exception('类型名称已被使用');
        }

        $type = Type::find($id);
        if (!empty($type)) {
            $typeNumber = $type->type_number;
        } else {
            $typeNumber = self::generateNumber();
        }
        $name = trim($typeArr['name'] ?? '');
        $image = trim($typeArr['image'] ?? '');

        $intro = trim($typeArr['intro'] ?? '');
        $warrantyStartType = trim($typeArr['warranty_start_type'] ?? '');
        if (!in_array($warrantyStartType, self::START_TYPE_CODES)) {
            throw new \Exception('质保类型错误');
        }

        $warrantyCycleCount = intval($typeArr['warranty_cycle_count'] ?? 0);
        if ($warrantyCycleCount <= 0) {
            throw new \Exception('质保时长错误');
        }

        $warrantyStartUnit = trim($typeArr['warranty_start_unit'] ?? '');
        if (!in_array($warrantyStartUnit, self::START_UNIT_CODES)) {
            throw new \Exception('质保周期错误');
        }

        // 知识库
        $articles = $typeArr['article_ids'] ?? [];
        $articleIds = [];
        foreach ($articles as $articleId) {
            $article = ArticleModel::find($articleId);
            if (empty($article)) {
                throw new \Exception("知识库文章不存在(ID: {$articleId})");
            }
            if (!empty($article)) {
                $articleIds[] = $articleId;
            }
        }

        // 配件
        $boms = $typeArr['boms'] ?? [];
        $typeBoms = [];
        if ($boms) {
            foreach ($boms as $itemBom) {
                $itemBomId = $itemBom['id'] ?? 0;
                $itemBomCount = $itemBom['count'] ?? 0;
                if ($itemBomId <= 0 || $itemBomCount <= 0) {
                    throw new \Exception("配件信息错误");
                }
                $bom = Bom::find($itemBomId);
                if (empty($bom)) {
                    throw new \Exception("配备不存在");
                }
                $typeBoms[] = [
                    'product_bom_id' => $itemBomId,
                    'count' => $itemBomCount
                ];
            }
        }
        $data = [
            'main_data' => [
                'category_id' => $categoryId,
                'type_number' => $typeNumber,
                'name' => $name,
                'image' => $image,
                'intro' => $intro,
                'warranty_start_type' => $warrantyStartType,
                'warranty_cycle_count' => $warrantyCycleCount,
                'warranty_start_unit' => $warrantyStartUnit,
                'create_user_id' => registry('user_id')
            ],
            'article_ids' => $articleIds,
            'boms' => $typeBoms
        ];
        return $data;
    }

    public static function destroy($id)
    {
        $type = Type::find($id);
        if (empty($type)) {
            throw new \Exception('类型不存在');
        }
        $bomsCount = $type->boms->count();
        $articleCount = $type->articles->count();
        if ($bomsCount > 0) {
            throw new \Exception(sprintf("该产品类型下有配件数量: %s, 不能删除", $bomsCount));
        }
        if ($articleCount > 0) {
            throw new \Exception(sprintf("该产品类型已绑定文章数量: %s, 不能删除", $articleCount));
        }
        $type->boms()->delete();
        $type->delete();
    }

    public static function generateNumber($typeId = 0)
    {
        $typeNumber = date('Ymd') . rand(1000000, 9999900);
        if ($typeId) {
            $type = Type::find($typeId);
            if (!empty($type)) {
                return $type->type_number;
            }
        }
        $productTypeCount = Type::byNumber($typeNumber)->count();
        if ($productTypeCount) {
            return self::generateNumber();
        }
        return $typeNumber;
    }
}